#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>
#include <variant>
#include <optional>
#include <sstream>
#include <type_traits>
#include <stdexcept>

class Cpp_Next {
public:
    using Value = std::variant<int, std::string, std::function<Value(const std::vector<Value>&)>>;
    using Result = std::variant<Value, std::string>;
    using Function = std::function<Result(const std::vector<std::string>&)>;

    Cpp_Next() {
        defineFunction("let", [this](const std::vector<std::string>& args) -> Result {
            if (args.size() >= 2) {
                std::string varName = args[0];
                std::string value = args[1];
                variables_[varName] = value;
                return varName;
            }
            return std::string("Error: Invalid arguments for let");
        });

        defineFunction("print", [this](const std::vector<std::string>& args) -> Result {
            for (const auto& arg : args) {
                if (variables_.count(arg)) {
                    std::visit([](auto&& val) { std::cout << val << ' '; }, variables_[arg]);
                } else {
                    std::cout << arg << ' ';
                }
            }
            std::cout << '\n';
            return {};
        });

        defineFunction("add", [this](const std::vector<std::string>& args) -> Result {
            if (args.size() == 2) {
                int a = std::stoi(args[0]);
                int b = std::stoi(args[1]);
                return a + b;
            }
            return std::string("Error: Invalid arguments for add");
        });

        defineFunction("define", [this](const std::vector<std::string>& args) -> Result {
            if (args.size() < 2) {
                return std::string("Error: Invalid arguments for define");
            }

            std::string funcName = args[0];
            std::vector<std::string> funcArgs(args.begin() + 1, args.end());
            functions_[funcName] = [this, funcArgs](const std::vector<std::string>& innerArgs) -> Result {
                for (size_t i = 0; i < funcArgs.size(); ++i) {
                    if (i < innerArgs.size()) {
                        variables_[funcArgs[i]] = innerArgs[i];
                    }
                }
                return std::string("Function defined");
            };
            return std::string("Function ") + funcName + " defined";
        });

        defineFunction("call", [this](const std::vector<std::string>& args) -> Result {
            if (args.empty()) {
                return std::string("Error: No function name provided");
            }

            std::string funcName = args[0];
            std::vector<std::string> funcArgs(args.begin() + 1, args.end());

            if (functions_.count(funcName)) {
                return functions_[funcName](funcArgs);
            }
            return std::string("Error: Function not found");
        });
    }

    void defineFunction(const std::string& name, Function func) {
        functions_[name] = func;
    }

    template<typename Func>
    void defineGenericFunction(const std::string& name, Func func) {
        functions_[name] = [func](const std::vector<std::string>& args) -> Result {
            return func(args);
        };
    }

    template<typename T>
    T getVariable(const std::string& name) {
        if (variables_.count(name)) {
            return std::get<T>(variables_[name]);
        }
        throw std::runtime_error("Variable not found");
    }

    Result run(const std::string& code) {
        auto tokens = tokenize(code);
        return executeCommand(tokens, 0);
    }

private:
    std::vector<std::string> tokenize(const std::string& code) {
        std::vector<std::string> tokens;
        std::string token;
        for (char ch : code) {
            if (isspace(ch)) {
                if (!token.empty()) {
                    tokens.push_back(token);
                    token.clear();
                }
            } else {
                token += ch;
            }
        }
        if (!token.empty()) tokens.push_back(token);
        return tokens;
    }

    Result executeCommand(const std::vector<std::string>& tokens, size_t start) {
        if (tokens.empty() || start >= tokens.size()) return std::string("Error: Empty or incomplete command");

        std::string command = tokens[start];
        if (functions_.count(command)) {
            auto result = functions_[command](std::vector<std::string>(tokens.begin() + start + 1, tokens.end()));
            std::visit(overloaded {
                [](const Value& val) {
                    std::visit([](auto&& arg) { std::cout << arg << ' '; }, val);
                },
                [](const std::string& err) {
                    std::cerr << err << '\n';
                }
            }, result);
            return result;
        }
        return std::string("Error: Unknown command");
    }

    template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
    template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

    std::unordered_map<std::string, Function> functions_;
    std::unordered_map<std::string, Value> variables_;
};

int main() {
    Cpp_Next script;

    // 定义一个高阶函数
    script.defineGenericFunction("map", [&script](const std::vector<std::string>& args) -> Cpp_Next::Result {
        if (args.size() < 2) {
            return std::string("Error: Invalid arguments for map");
        }

        std::string funcName = args[0];
        std::vector<Cpp_Next::Value> mappedValues;
        for (size_t i = 1; i < args.size(); ++i) {
            auto result = script.run("call " + funcName + " " + args[i]);
            if (std::holds_alternative<Cpp_Next::Value>(result)) {
                mappedValues.push_back(std::get<Cpp_Next::Value>(result));
            } else {
                return std::string("Error: Function call failed");
            }
        }
        return mappedValues;
    });

    // 定义一个简单的函数
    script.run("define inc x add x 1");

    // 使用高阶函数 map
    auto result = script.run("map inc 1 2 3 4 5");
    if (std::holds_alternative<Cpp_Next::Value>(result)) {
        std::visit([](auto&& val) {
            for (const auto& v : val) {
                std::visit([](auto&& arg) { std::cout << arg << ' '; }, v);
            }
            std::cout << '\n';
        }, std::get<Cpp_Next::Value>(result));
    } else if (std::holds_alternative<std::string>(result)) {
        std::cerr << std::get<std::string>(result) << '\n';
    }

    return 0;
}

